package com.clms.rents.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.IpUtils;
import com.clms.common.JwtUtils;
import com.clms.common.util.Payload;
import com.clms.rents.config.RsaKeyProperties;
import com.clms.rents.mapper.TabSysLogMapper;
import com.clms.rents.pojo.entity.SysOperLog;
import com.clms.rents.pojo.entity.SysUser;
import com.clms.rents.util.IPUtils;
import com.clms.rents.util.WebUtil;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.net.util.IPAddressUtil;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @program: clms-fourth
 * @description: 日志切面
 * @author: 于朋博
 * @create: 2021-07-27 14:48
 **/
@Aspect
@Component
@Slf4j
public class SysLogAspect {
    @Lazy
    @Resource
    private TabSysLogMapper logMapper;

    //访问类
    private Class clazz;
    @Lazy
    @Resource
    private RsaKeyProperties rsaKeyProperties;


//
//    @Lazy
//    @Resource
//    private HttpSessionService httpSessionService;

    /**
     * 此处的切点是注解的方式
     * 只要出现 @LogAnnotation注解都会进入
     */
//    @Pointcut("execution(* com.clms.rents.controller.*.*(..))")


    @Pointcut("@annotation(com.clms.rents.aop.LogAnnotation)")
    public void logPointCut() {

    }

    /**
     * 环绕增强,相当于MethodInterceptor
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point)throws Throwable {
        long beginTime = System.currentTimeMillis();
        //执行方法
        Object result = point.proceed();
        //执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;

        //保存日志
        try {
            saveSysLog(point, time);
        }catch (Exception e) {
            log.error("sysLog,exception:{}", e, e);
        }

        return result;
    }

    /**
     * 把日志保存
     */
    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        SysOperLog sysLog = new SysOperLog();
        LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
        if (logAnnotation !=null) {
            //注解上的描述
            sysLog.setTitle(logAnnotation.title());
            //注解上的业务类型赋值给实体
            log.info("方法的业务类型"+logAnnotation.businessType());
            System.out.println(logAnnotation.businessType());
            sysLog.setBusinessType(Integer.parseInt(logAnnotation.businessType()));
            sysLog.setDeptName(logAnnotation.ziMenu());
        }

        //请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className +"." + methodName +"()");
        log.info("请求{}.{}耗时{}毫秒", className, methodName, time);
        try {
            //请求的参数
            Object[] args = joinPoint.getArgs();
            String params =null;
            if (args.length !=0) {
                params = JSON.toJSONString(args);
            }
//           log.info("打印请求的参数"+args.toString());
//           log.info("大印参数2"+params);

            sysLog.setOperParam(params);
        }catch (Exception e) {
            log.error("sysLog,exception:{}", e, e);
        }
        //获取request
//        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//        HttpServletRequest request = WebUtil.getRequest();
        ServletRequestAttributes requestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes( );
        HttpServletRequest request = requestAttributes.getRequest();

        //设置IP地址
        sysLog.setOperIp(request.getRemoteAddr());

        if (internalIp(request.getRemoteAddr())) {
            sysLog.setOperLocation("内网Ip");
        } else {
            sysLog.setOperLocation("外网Ip");
        }
        log.info("Ip{}，接口地址{}，请求方式{}，入参：{}", sysLog.getOperIp(),
                request.getRequestURL(), request.getMethod(), sysLog.getOperParam());
        //用户名
//        String userId = httpSessionService.getCurrentUserId();
//        String username = httpSessionService.getCurrentUsername();
//        sysLog.setUsername(username);
//        sysLog.setUserId(userId);

        log.info("请求Ip" + request.getRemoteAddr());
        log.info("请求地址"+request.getRequestURI());

        log.info(sysLog.toString());
        sysLog.setOperUrl(request.getRequestURI());
        Date day=new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.info("系统当前时间:"+day);
        sysLog.setOperTime(df.format(day));
        //获取操作人信息
        HttpServletRequest request1=WebUtil.getRequest();
        String token=request1.getHeader("token");
        Payload<SysUser> infoFromToken = JwtUtils.getInfoFromToken(token, rsaKeyProperties.getPublicKey(), SysUser.class);
                   sysLog.setOperName(infoFromToken.getUserInfo().getUserName());
        logMapper.insert(sysLog);

    }
    public static boolean internalIp(String ip) {
        byte[] addr = IPAddressUtil.textToNumericFormatV4(ip);
        return internalIp(addr);
    }


    public static boolean internalIp(byte[] addr) {
        final byte b0 = addr[0];
        final byte b1 = addr[1];
        //10.x.x.x/8
        final byte SECTION_1 = 0x0A;
        //172.16.x.x/12
        final byte SECTION_2 = (byte) 0xAC;
        final byte SECTION_3 = (byte) 0x10;
        final byte SECTION_4 = (byte) 0x1F;
        //192.168.x.x/16
        final byte SECTION_5 = (byte) 0xC0;
        final byte SECTION_6 = (byte) 0xA8;
        switch (b0) {
            case SECTION_1:
                return true;
            case SECTION_2:
                if (b1 >= SECTION_3 && b1 <= SECTION_4) {
                    return true;
                }
            case SECTION_5:
                switch (b1) {
                    case SECTION_6:
                        return true;
                }
            default:
                return false;

        }
    }

}



